#include <mips/regdef.h>

#define FT_ERROR_MSG	360	
#define FT_LINE_NUMBER	356	
#define FT_TAGS_POINTER	532	
#define FT_TAG_COUNT	348	
#define FT_LAST_POSITION 344	
#define FT_START_INDEX	340	
#define FT_TEXT			336

#define FT_SSIZE		336
#define	FT_RA			332
#define FT_FP			328
#define FT_GP			324
#define FT_S0			320

#define FT_MSG_BUFFER	64	
#define	FT_CLOSE_TAG_NAME	60
#define FT_OPEN_TAG_NAME	56
#define FT_TAG_LENGTH_RESULT  52		
#define FT_OPEN_TAG_RESULT	48
#define FT_FIND_TAG_RESULT	44
#define FT_RESULT		40

#define FT_LOCAL_ERROR_MSG	24
#define FT_LOCAL_L_NUMBER	20
#define FT_LOCAL_TAGS_PNTR	16

	.rdata
	.align	2
MSGFORMAT:
	.ascii	"Error en linea %d: %s cerrado antes que %s\000"
	.text
	.align	2
	.globl	findTag
	.ent	findTag
findTag:
	.frame	$fp,FT_TEXT,ra		
	.mask	0xd0010000,-4
	.fmask	0x00000000,0
	.set	noreorder
	.cpload	t9
	.set	reorder
	subu	sp,sp,FT_TEXT           #Crear stack
	.cprestore 32
	sw	ra,FT_RA(sp)                #Guardo registros del SRA
	sw	$fp,FT_FP(sp)
	sw	gp,FT_GP(sp)
	sw	s0,FT_S0(sp)
	move	$fp,sp
	sw	a0,FT_TEXT($fp)             #Guardar argumentos en ABA del caller
	sw	a1,FT_START_INDEX($fp)
	sw	a2,FT_LAST_POSITION($fp)
	sw	a3,FT_TAG_COUNT($fp)
	sw	zero,FT_RESULT($fp)
	
    lw	a0,FT_TEXT($fp)             #Inicializo los valores para la llamada a findInnerTag
	lw	a1,FT_START_INDEX($fp)
	lw	a2,FT_LAST_POSITION($fp)
	lw	a3,FT_LINE_NUMBER($fp)
	la	t9,findTagInner
	jal	ra,t9                       #Busco el siguiente tag
	sw	v0,FT_FIND_TAG_RESULT($fp)  #Guardo resultado en el stack
	lw	v0,FT_FIND_TAG_RESULT($fp)
	beq	v0,zero,SALIR               #Si no lo encuentro, salir
	lw	a0,FT_FIND_TAG_RESULT($fp)  #Cargo en a0 el resultado de findTagInner
	la	t9,isOpenTag                #Verifico si es un tag de apertura
	jal	ra,t9
	sw	v0,FT_OPEN_TAG_RESULT($fp)
	lw	v1,FT_OPEN_TAG_RESULT($fp)
	li	v0,1			            #Carga en la salida el valor 0x1
	bne	v1,v0,IS_CLOSE_TAG          #Si es tag de cierre salto
	lw	a0,FT_FIND_TAG_RESULT($fp)  #Caso contrario, encolo
	la	t9,strlen
	jal	ra,t9
	sw	v0,FT_TAG_LENGTH_RESULT($fp) #Obtengo la longitud del tag
	lw	v0,FT_TAGS_POINTER($fp)     #Cargo el puntero a la lista de tags
	lw	v0,0(v0)                    #Desreferencio y cargo el valor del puntero al primer tag
	sll	v1,v0,2                     #Multiplico por 4 para convertirlo en un offset
	lw	v0,FT_TAG_COUNT($fp)        #Cargo el valor del tagCount
	addu	s0,v1,v0                #Sumo al offset el valor de tagCount
	lw	v0,FT_TAG_LENGTH_RESULT($fp)
	addu	v0,v0,1                 #Incremento en 1 la cantidad de memoria a alocar
	move	a0,v0
	la	t9,malloc
	jal	ra,t9
	sw	v0,0(s0)                    #Guardo el puntero a la memoria alocada en s0
	lw	v0,FT_TAGS_POINTER($fp)     #Cargo en v0 el puntero a los tags
	lw	v0,0(v0)                    #Desreferencio
	sll	v1,v0,2                     #Convierto en offset
	lw	v0,FT_TAG_COUNT($fp)   
	addu	v0,v1,v0                #Sumo tagCount al offset del puntero a tags
	lw	a0,0(v0)                    #Desreferencio
	lw	a1,FT_FIND_TAG_RESULT($fp)
	la	t9,strcpy                   #Copio en la posicion del array de tags apuntado
	jal	ra,t9                       #por a0, el valor apuntado por a1
	lw	v1,FT_TAGS_POINTER($fp)
	lw	v0,FT_TAGS_POINTER($fp)
	lw	v0,0(v0)
	addu	v0,v0,1
	sw	v0,0(v1)                    #Incrementa tagCount en 1.
	b	CORTE
IS_CLOSE_TAG:
	lw	v0,FT_TAGS_POINTER($fp)
	lw	v0,0(v0)
	sll	v1,v0,2
	lw	v0,FT_TAG_COUNT($fp)
	addu	v0,v1,v0
	addu	v0,v0,-4                #Me posiciono en el tag anterior
	lw	v0,0(v0)                    #Desreferencio el tag
	sw	v0,FT_TAG_LENGTH_RESULT($fp) #Guardo puntero al last open tag
	lw	a0,FT_TAG_LENGTH_RESULT($fp) #Obtengo puntero al last open tag
	la	t9,getTagName               #Obtengo el nombre del tag de apertura de la cola
	jal	ra,t9
	sw	v0,FT_OPEN_TAG_NAME($fp)
	lw	a0,FT_FIND_TAG_RESULT($fp)
	la	t9,getTagName               #Obtengo el nombre del tag de cierre
	jal	ra,t9
	sw	v0,FT_CLOSE_TAG_NAME($fp)
	lw	a0,FT_OPEN_TAG_NAME($fp)
	lw	a1,FT_CLOSE_TAG_NAME($fp)
	la	t9,strcmp                   #Comparo ambos nombres
	jal	ra,t9
	beq	v0,zero,CONTINUE            #Si son iguales esta bien cerrado y continuo
	li	v0,1			            #Si no, agrego mensaje en errores
	sw	v0,FT_RESULT($fp)
	addu	v1,$fp,FT_MSG_BUFFER    #Apunto al espacio para el msgBuffer
	lw	a2,FT_LINE_NUMBER($fp)
	lw	v0,FT_OPEN_TAG_NAME($fp)
	sw	v0,16(sp)
	move	a0,v1                   #Asigno el msgBuffer al parametro de sprintf
	la	a1,MSGFORMAT
	lw	a2,0(a2)
	lw	a3,FT_CLOSE_TAG_NAME($fp)
	la	t9,sprintf
	jal	ra,t9
	lw	v1,FT_ERROR_MSG($fp)
	addu	v0,$fp,FT_MSG_BUFFER    #Apunto a la dir del msgBuffer y guardo el mensaje
	sw	v0,0(v1)                    #formateado en la dir apuntada por v1. (ERROR_MSG)
CONTINUE:
	lw	v0,FT_TAGS_POINTER($fp)     #Libera los punteros a los nombres
	lw	v0,0(v0)
	sll	v1,v0,2
	lw	v0,FT_TAG_COUNT($fp)
	addu	v0,v1,v0
	addu	v0,v0,-4
	lw	a0,0(v0)
	la	t9,free
	jal	ra,t9
	lw	v1,FT_TAGS_POINTER($fp)
	lw	v0,FT_TAGS_POINTER($fp)
	lw	v0,0(v0)
	addu	v0,v0,-1
	sw	v0,0(v1)
	lw	a0,FT_OPEN_TAG_NAME($fp)
	la	t9,free
	jal	ra,t9
	lw	a0,FT_CLOSE_TAG_NAME($fp)
	la	t9,free
	jal	ra,t9
CORTE:
	lw	v0,FT_RESULT($fp)
	bne	v0,zero,SALIR               #Si no hubo errores inicio recursividad
	lw	v1,FT_LAST_POSITION($fp)
	lw	v0,FT_TAGS_POINTER($fp)
	sw	v0,FT_LOCAL_TAGS_PNTR(sp)
	lw	v0,FT_LINE_NUMBER($fp)
	sw	v0,FT_LOCAL_L_NUMBER(sp)
	lw	v0,FT_ERROR_MSG($fp)
	sw	v0,FT_LOCAL_ERROR_MSG(sp)
	lw	a0,FT_TEXT($fp)             #a0: text
	lw	a1,0(v1)                    #a1: *lastPosition
	lw	a2,FT_LAST_POSITION($fp)    #a2: lastPosition
	lw	a3,FT_TAG_COUNT($fp)        #a3: tagCount
	la	t9,findTag
	jal	ra,t9
	sw	v0,FT_RESULT($fp)
SALIR:
	lw	a0,FT_FIND_TAG_RESULT($fp)
	la	t9,free
	jal	ra,t9
	lw	v0,FT_RESULT($fp)          #Cargo el resultado para devolverlo
	move	sp,$fp
	lw	ra,FT_RA(sp)               #Vuelvo a cargar los registros del micro
	lw	$fp,FT_FP(sp)
	lw	s0,FT_S0(sp)   
	addu	sp,sp,FT_TEXT          #Destruyo stack
	j	ra                         #Vuelvo
	.end	findTag
